package com.youlu.campus.service.activity.impl;

import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.req.ActivityPayConfigVO;
import com.youlu.campus.entity.VO.req.ActivityPayCopy;
import com.youlu.campus.entity.VO.req.CopyPayConfigPageReq;
import com.youlu.campus.entity.VO.req.QueryPayConfigVO;
import com.youlu.campus.entity.course.UserAllTopRecordService;
import com.youlu.campus.entity.course.entity.UserAllTopRecord;
import com.youlu.campus.service.cache.CacheActivityService;
import com.youlu.campus.service.cache.CachePayConfigService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.postage.PostageTemplateService;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ActivityPayConfigService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CachePayConfigService cachePayConfigService;

    @Autowired
    private CacheActivityService activityService;
    @Autowired
    private PostageTemplateService postageTemplateService;
    @Autowired
    private PlatformConfigService platformConfigService;

    @Lazy
    @Autowired
    private ActivityPayButtonConfigService activityPayButtonConfigService;

    @Autowired
    private UserAllTopRecordService userAllTopRecordService;

    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;


    /**
     * 收款链接
     */
    public static final String activityPayUrl = "#/pages/activity-reward?activityId=%s&theme=%s&type=1&appId=%s&scope" +
            "=snsapi_base" +
            "&rewardType=0";
    /**
     * 收款链接V2
     */
    public static final String activityV2PayUrl = "#/pages/activity-reward/index?activityId=%s&theme=%s&type=1&appId=%s&scope" +
            "=snsapi_base" +
            "&rewardType=0";

    public void payCopy(ActivityPayCopy activityPayCopy) {
        String sourceActivityId = activityPayCopy.getSourceActivityId();
        String targetActivityId = activityPayCopy.getTargetActivityId();
        log.error("【copy 支付配置页】 start sourceActivityId:{}| targetActivityId:{}", sourceActivityId, targetActivityId);
        PayConfigPage sourcePayConfigPage = cachePayConfigService.findByActivityId(sourceActivityId);
        if (Objects.isNull(sourcePayConfigPage)) {
            log.error("【copy 支付配置页】 找不到sourceActivityId:{}", sourceActivityId);
            return;
        }
        PayConfigPage targetPayConfigPageExist = cachePayConfigService.findByActivityId(targetActivityId);
        if (Objects.nonNull(targetPayConfigPageExist)) {
            throw new BusinessException("复制目标活动已经存在");
        }
        ActivityInfo targetActivityInfo = activityService.findById(targetActivityId);
        if (Objects.isNull(targetActivityInfo)) {
            throw new BusinessException("复制目标活动不存在");
        }
        PayConfigPage targetPayConfig = mapperFacade.map(sourcePayConfigPage, PayConfigPage.class);
        targetPayConfig.setId(null);
        targetPayConfig.setActivityId(targetActivityId);
        targetPayConfig.setActivityName(targetActivityInfo.getName());
        Date now = new Date();
        targetPayConfig.setCreatedTime(now);
        targetPayConfig.setUpdatedTime(now);
        this.mongoTemplate.save(targetPayConfig);
        log.error("【copy 支付配置页】 end sourceActivityId:{}| targetActivityId:{}", sourceActivityId, targetActivityId);
    }

    public void save(ActivityPayConfigVO payButtonConfig) {
        String id = payButtonConfig.getId();
        PayConfigPage payConfigPage = null;
        if (StringUtils.isNotBlank(id)) {
            payConfigPage = this.mongoTemplate.findById(id, PayConfigPage.class);
            if (Objects.nonNull(payConfigPage)) {
                payConfigPage.setUpdatedTime(new Date());
                cachePayConfigService.delete(payConfigPage.getActivityId());
            }
        }
        if (Objects.isNull(payConfigPage)) {
            payConfigPage = new PayConfigPage();
            payConfigPage.setCreatedTime(new Date());
        }
        BeanUtils.copyProperties(payButtonConfig, payConfigPage);
        mongoTemplate.save(payConfigPage);
    }

    public Page<PayConfigPage> list(QueryPayConfigVO queryPayConfig) {
        Query query = new Query();
        String activityId = queryPayConfig.getActivityId();
        List<String> ids = new ArrayList<>();
        if (StringUtils.isNotBlank(activityId)) {
            query.addCriteria(Criteria.where("activityId").is(activityId));
            ids = mongoTemplate.find(query, PayConfigPage.class).stream().map(PayConfigPage::getId).collect(Collectors.toList());
        }
        PageRequest pageRequest = PageRequest.of(queryPayConfig.getPageNo() - 1, queryPayConfig.getPageSize());
        long count = this.mongoTemplate.count(query, PayConfigPage.class);
        if (count == 0) {
            return PageableExecutionUtils.getPage(new ArrayList<>(), pageRequest, () -> count);
        }

        Pair<Long, List<UserAllTopRecord>> pair = userAllTopRecordService.getUserTopRecordList(queryPayConfig.getUserId(), ids);
        long topSize = pair.getLeft();
        List<String> existIds = pair.getRight().stream().map(UserAllTopRecord::getUniqueId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(existIds)) {
            query.addCriteria(Criteria.where("id").nin(existIds));
        }
        long start = (queryPayConfig.getPageNo() - 1) * queryPayConfig.getPageSize();
        long end = queryPayConfig.getPageNo() * queryPayConfig.getPageSize();
        List<PayConfigPage> list = new LinkedList<>();
        if (end <= topSize) {
            list.addAll(getTopList(pair.getRight()).stream().skip(start).limit(queryPayConfig.getPageSize()).collect(Collectors.toList()));
            return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
        } else if (topSize > start && topSize < end) {
            list.addAll(getTopList(pair.getRight()).stream().skip(start).limit(topSize - start).collect(Collectors.toList()));
            query.skip(0).limit((int) (end - topSize));
        } else {
            query.skip(start - topSize).limit(pageRequest.getPageSize());
        }
        PlatformConfig platformConfig=platformConfigService.find();
        String payCatalogue = platformConfigService.getPayCatalogue();
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort=Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<PayConfigPage> other = this.mongoTemplate.find(query, PayConfigPage.class);
        other.stream().forEach(payConfigPage -> {
            String appId = payConfigPage.getAppId();
            WechatConfigInfo wechatConfigInfo=wechatConfigInfoService.find(appId);
//            if("wechat-mini".equals(wechatConfigInfo.getPlatform())){
                ActivityInfo activityInfo = activityService.findById(payConfigPage.getActivityId());
                payConfigPage.setWechatPayUrl(platformConfigService.getBizFrontPayDomain() + payCatalogue + String.format(activityPayUrl, payConfigPage.getActivityId(), activityInfo.getThemeColor(), appId));
                payConfigPage.setWechatPayV2Url(platformConfigService.getBizFrontPayDomain() + payCatalogue + String.format(activityV2PayUrl, payConfigPage.getActivityId(), activityInfo.getThemeColor(), appId));
                //            payConfigPage.setWechatPayUrl(platformConfigService.getBizFrontPayDomain() + String.format
//            (activityPayUrl, payConfigPage.getActivityId(), activityInfo.getThemeColor(), appId));
                payConfigPage.setActivityName(activityInfo.getName());
//            }
        });
        list.addAll(other);
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    public List<PayConfigPage> getTopList(List<UserAllTopRecord> records) {
        List<String> ids = records.stream().map(UserAllTopRecord::getUniqueId).distinct().collect(Collectors.toList());
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("id").in(ids));
        List<PayConfigPage> pgList = this.mongoTemplate.find(query1, PayConfigPage.class);
        Map<String, PayConfigPage> recordMap = pgList.stream().collect(Collectors.toMap(PayConfigPage::getId, Function.identity(), (o1, o2) -> o2));
        String payCatalogue = platformConfigService.getPayCatalogue();
        List<PayConfigPage> list=new ArrayList<>();
        for(UserAllTopRecord item:records){
            PayConfigPage payConfigPage = recordMap.get(item.getUniqueId());
            if (Objects.nonNull(payConfigPage)) {
                payConfigPage.setOnTop(item.getOnTop());
                String appId = payConfigPage.getAppId();
                ActivityInfo activityInfo = activityService.findById(payConfigPage.getActivityId());
                payConfigPage.setWechatPayUrl(platformConfigService.getBizFrontPayDomain() + payCatalogue + String.format(activityPayUrl, payConfigPage.getActivityId(), activityInfo.getThemeColor(), appId));
                payConfigPage.setActivityName(activityInfo.getName());
                list.add(payConfigPage);
            }
        }
//        List<PayConfigPage> list = records.stream().map(item -> {
//            PayConfigPage payConfigPage = recordMap.get(item.getUniqueId());
//            if (Objects.nonNull(payConfigPage)) {
//                payConfigPage.setOnTop(item.getOnTop());
//                String appId = payConfigPage.getAppId();
//                ActivityInfo activityInfo = activityService.findById(payConfigPage.getActivityId());
//                payConfigPage.setWechatPayUrl(platformConfigService.getBizFrontPayDomain() + payCatalogue + String.format(activityPayUrl, payConfigPage.getActivityId(), activityInfo.getThemeColor(), appId));
//                payConfigPage.setActivityName(activityInfo.getName());
//
//            }
//            return payConfigPage;
//        }).collect(Collectors.toList());
        return list;
    }

    public PayConfigPage detail(String id) {
        PayConfigPage p = mongoTemplate.findById(id, PayConfigPage.class);
        if (Objects.nonNull(p) && StringUtils.isNotBlank(p.getPostageTemplateId())) {
            PostageTemplate postageTemplate = postageTemplateService.findOne(p.getPostageTemplateId());
            if (Objects.nonNull(postageTemplate)) {
                p.setPostageTemplateName(postageTemplate.getName());
            }
        }
        return p;
    }

    public void delete(String id) {

        Query query = new Query();
        query.addCriteria(Criteria.where("payConfigPageId").is(id));
        long count = this.mongoTemplate.count(query, PayButtonConfigPage.class);
        if (count > 0) {
            throw new BusinessException("该活动配置页有存在按按钮配置页,不能删除,如要删除,请先删除按钮配置页");
        }
        PayConfigPage payConfigPage = this.mongoTemplate.findById(id, PayConfigPage.class);
        if (Objects.isNull(payConfigPage)) {
            return;
        }
        this.mongoTemplate.remove(new Query().addCriteria(Criteria.where("id").is(id)), PayConfigPage.class);
        cachePayConfigService.delete(payConfigPage.getActivityId());
    }

    public PayConfigPage findByActivityId(String activityId, Integer type) {
        log.info("获取活动->{}支付配置 类型->{}", activityId, type);
        PayConfigPage payConfigPage = cachePayConfigService.findByActivityId(activityId);
        if (Objects.isNull(payConfigPage)) {
            log.error(":>>> 活动收款配置不存在，请配置:{}",activityId);
            throw new BusinessException("该活动支付配置页不存在");
        }
        String id = payConfigPage.getId();
        List<PayButtonConfigPage> list = cachePayConfigService.findByPayConfigPageIdAndType(id, type);
        if (CollectionUtils.isEmpty(list)) {
            throw new BusinessException("该活动支付配置页按钮不存在");
        }
        list = list.stream().map(button -> {
            String certificateConfigId = button.getCertificateConfigId();
            if (StringUtils.isNotBlank(certificateConfigId)) {
                CertificateActivityConfig certificateActivityConfig = findCertificateById(certificateConfigId);
                if (Objects.nonNull(certificateActivityConfig)) {
                    button.setCaType(certificateActivityConfig.getCaType());
                }
            }
            return button;
        }).collect(Collectors.toList());
        payConfigPage.setPayButtonConfigList(list);
        return payConfigPage;
    }

    private CertificateActivityConfig findCertificateById(String id) {
        return this.mongoTemplate.findById(id, CertificateActivityConfig.class);
    }

    public PayConfigPage findByActivityId(String activityId) {
        return cachePayConfigService.findByActivityId(activityId);
    }

    /**
     * 复制支付配置
     *
     * @param copyActivityId
     * @param newActivityId
     */
    public void doCopyPayConfig(String copyActivityId, String newActivityId) {
        log.info("【copy 活动】开始复制活动支付配置->{} copyActivityId", copyActivityId);
        Query query = new Query().addCriteria(Criteria.where("activityId").is(copyActivityId));
        PayConfigPage payConfigPage = this.mongoTemplate.findOne(query, PayConfigPage.class);
        if (Objects.isNull(payConfigPage)) {
            log.error("【copy 活动】结束复制活动支付配置->{} 已结束 copyActivityId", copyActivityId);
            return;
        }
        Date now = new Date();
        String oldPayConfigPageId = payConfigPage.getId();
        payConfigPage.setId(ObjectId.get().toString());
        payConfigPage.setCreatedTime(now);
        payConfigPage.setUpdatedTime(now);
        payConfigPage.setActivityId(newActivityId);
        this.mongoTemplate.save(payConfigPage);
        CopyPayConfigPageReq copyPayConfigPageReq = new CopyPayConfigPageReq();
        copyPayConfigPageReq.setCopyActivityId(copyActivityId);
        copyPayConfigPageReq.setNewActivityId(newActivityId);
        copyPayConfigPageReq.setNewPayConfigPageId(payConfigPage.getId());
        copyPayConfigPageReq.setOldPayConfigPageId(oldPayConfigPageId);
        activityPayButtonConfigService.doCopyPayButtonConfig(copyPayConfigPageReq);
        log.info("【copy 活动】结束复制活动支付配置->{} copyActivityId", copyActivityId);
    }

}
